frontend/pages/e/[uuid]/details.tsx (view raw)
1import moment from 'moment';
2import Button from '@mui/material/Button';
3import Box from '@mui/material/Box';
4import Link from '@mui/material/Link';
5import Paper from '@mui/material/Paper';
6import Divider from '@mui/material/Divider';
7import Container from '@mui/material/Container';
8import TextField from '@mui/material/TextField';
9import Typography from '@mui/material/Typography';
10import {useTheme} from '@mui/material/styles';
11import {DatePicker} from '@mui/x-date-pickers/DatePicker';
12import {PropsWithChildren, useState} from 'react';
13import {useTranslation} from 'react-i18next';
14import pageUtils from '../../../lib/pageUtils';
15import ShareEvent from '../../../containers/ShareEvent';
16import useEventStore from '../../../stores/useEventStore';
17import useToastStore from '../../../stores/useToastStore';
18import useSettings from '../../../hooks/useSettings';
19import EventLayout, {TabComponent} from '../../../layouts/Event';
20import {
21 EventByUuidDocument,
22 useUpdateEventMutation,
23} from '../../../generated/graphql';
24
25interface Props {
26 eventUUID: string;
27 announcement?: string;
28}
29
30const Page = (props: PropsWithChildren<Props>) => {
31 return <EventLayout {...props} Tab={DetailsTab} />;
32};
33
34const DetailsTab: TabComponent = ({}) => {
35 const {t} = useTranslation();
36 const theme = useTheme();
37 const settings = useSettings();
38 const [updateEvent] = useUpdateEventMutation();
39 const addToast = useToastStore(s => s.addToast);
40 const setEventUpdate = useEventStore(s => s.setEventUpdate);
41 const event = useEventStore(s => s.event);
42 const [isEditing, setIsEditing] = useState(false);
43 const idPrefix = isEditing ? 'EditEvent' : 'Event';
44
45 const onSave = async e => {
46 try {
47 const {uuid, ...data} = event;
48 const {id, travels, waitingPassengers, __typename, ...input} = data;
49 await updateEvent({
50 variables: {uuid, eventUpdate: input},
51 refetchQueries: ['eventByUUID'],
52 });
53 setIsEditing(false);
54 } catch (error) {
55 console.error(error);
56 addToast(t('event.errors.cant_update'));
57 }
58 };
59 const sectionSx = {
60 marginBottom: theme.spacing(2),
61 width: '540px',
62 maxWidth: '100%',
63 paddingX: theme.spacing(2),
64 };
65
66 const modifyButton = isEditing ? (
67 <Button
68 variant="contained"
69 color="primary"
70 sx={{position: 'absolute', right: theme.spacing(2)}}
71 onClick={onSave}
72 >
73 {t('event.details.save')}
74 </Button>
75 ) : (
76 <Button
77 variant="text"
78 color="primary"
79 sx={{position: 'absolute', right: theme.spacing(2)}}
80 onClick={() => setIsEditing(true)}
81 >
82 {t('event.details.modify')}
83 </Button>
84 );
85
86 if (!event) return null;
87
88 return (
89 <Box
90 sx={{
91 position: 'relative',
92 paddingLeft: '80px',
93
94 [theme.breakpoints.down('md')]: {
95 paddingLeft: 0,
96 paddingBottom: '80px',
97 },
98 }}
99 >
100 <Container maxWidth="sm" sx={{marginTop: theme.spacing(6)}}>
101 <Paper sx={{position: 'relative', padding: theme.spacing(2)}}>
102 {modifyButton}
103 <Box sx={sectionSx}>
104 <Typography variant="h6">{t('event.fields.name')}</Typography>
105 {isEditing ? (
106 <TextField
107 fullWidth
108 value={event.name}
109 onChange={e => setEventUpdate({name: e.target.value})}
110 name="name"
111 id="EditEventName"
112 />
113 ) : (
114 <Typography variant="body1" id={`${idPrefix}Name`}>
115 {event.name ?? t('event.fields.empty')}
116 </Typography>
117 )}
118 </Box>
119 <Box sx={sectionSx}>
120 <Typography variant="h6">{t('event.fields.date')}</Typography>
121 {isEditing ? (
122 <DatePicker
123 renderInput={props => (
124 <TextField
125 {...props}
126 id={`${idPrefix}Date`}
127 fullWidth
128 placeholder={t('event.fields.date_placeholder')}
129 />
130 )}
131 value={event.date}
132 onChange={date =>
133 setEventUpdate({
134 date: !date ? null : moment(date).format('YYYY-MM-DD'),
135 })
136 }
137 />
138 ) : (
139 <Typography variant="body1" id={`${idPrefix}Date`}>
140 {event.date
141 ? moment(event.date).format('DD/MM/YYYY')
142 : t('event.fields.empty')}
143 </Typography>
144 )}
145 </Box>
146 <Box sx={sectionSx}>
147 <Typography variant="h6">{t('event.fields.address')}</Typography>
148 {isEditing ? (
149 <TextField
150 fullWidth
151 multiline
152 maxRows={4}
153 inputProps={{maxLength: 250}}
154 helperText={`${event.address?.length ?? 0}/250`}
155 defaultValue={event.address}
156 value={event.address}
157 onChange={e => setEventUpdate({address: e.target.value})}
158 id={`${idPrefix}Address`}
159 name="address"
160 />
161 ) : (
162 <Typography variant="body1" id={`${idPrefix}Address`}>
163 {event.address ? (
164 <Link
165 target="_blank"
166 rel="noreferrer"
167 href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(
168 event.address
169 )}`}
170 onClick={e => e.preventDefault}
171 >
172 {event.address}
173 </Link>
174 ) : (
175 t('event.fields.empty')
176 )}
177 </Typography>
178 )}
179 </Box>
180 <Box sx={sectionSx}>
181 <Typography variant="h6">
182 {t('event.fields.description')}
183 </Typography>
184 {isEditing ? (
185 <TextField
186 fullWidth
187 multiline
188 maxRows={4}
189 inputProps={{maxLength: 250}}
190 helperText={`${event.description?.length || 0}/250`}
191 defaultValue={event.description}
192 value={event.description || ''}
193 onChange={e => setEventUpdate({description: e.target.value})}
194 id={`${idPrefix}Description`}
195 name="description"
196 />
197 ) : (
198 <Typography variant="body1" id={`${idPrefix}Description`}>
199 {event.description ?? t('event.fields.empty')}
200 </Typography>
201 )}
202 </Box>
203 <Box sx={sectionSx}>
204 <Typography variant="h6">{t('event.fields.link')}</Typography>
205 <Typography>{t('event.fields.link_desc')}</Typography>
206 </Box>
207 <Box py={4} justifyContent="center" display="flex">
208 <ShareEvent
209 title={`Caroster ${event.name}`}
210 url={`${window.location.href}`}
211 />{' '}
212 </Box>
213 <Divider variant="middle" />
214 <Box pt={2} justifyContent="center" display="flex">
215 <Link href={settings?.about_link} target="_blank" rel="noopener">
216 {t('event.details.aboutCaroster')}
217 </Link>
218 </Box>
219 </Paper>
220 </Container>
221 </Box>
222 );
223};
224
225export const getServerSideProps = pageUtils.getServerSideProps(
226 async (context, apolloClient) => {
227 const {uuid} = context.query;
228 const {host = ''} = context.req.headers;
229 let event = null;
230
231 // Fetch event
232 try {
233 const {data} = await apolloClient.query({
234 query: EventByUuidDocument,
235 variables: {uuid},
236 });
237 event = data?.eventByUUID?.data;
238 } catch (error) {
239 return {
240 notFound: true,
241 };
242 }
243
244 return {
245 props: {
246 eventUUID: uuid,
247 metas: {
248 title: event?.attributes?.name || '',
249 url: `https://${host}${context.resolvedUrl}`,
250 },
251 },
252 };
253 }
254);
255export default Page;